package policy

import (
	"emsctrl/pid"
	"emsctrl/public"
	"fmt"
	"math"
	"reflect"
	"runtime"
)

type Peak_load_shift struct {
	P *public.CurrentPolicy
}

func (p *Peak_load_shift) ParaSet(policy *public.CurrentPolicy) {
	//TODO implement me
	fmt.Println("implement me")
	p.P = policy
}

func (p *Peak_load_shift) Run() bool {
	//TODO implement me
	fmt.Println("Peak_load_shift run")
	check := p.PcsRemote_check()
	if check == true {
		alarmProcess, process := p.FaultAlarm_Process()
		if process == false {
			return false
		}
		if alarmProcess == true {
			p.Policy_Process()
		} else {
			p.stop_proc()
		}
	}
	return true
}

func (p *Peak_load_shift) PcsRemote_check() bool {
	if p.P.RemoteSignal.PcsRemoteState == 1 {
		return true
	} else {
		p.P.RunModeSel.PcsRemoteSet()
		return false
	}
}

func (p *Peak_load_shift) FaultAlarm_Process() (bool, bool) {
	//TODO implement me
	fmt.Println("FaultAlarm_Process me")
	fmt.Println(p.P.RemoteSignal.PcsFaultState, p.P.RemoteSignal.PcsAlarmState)
	valueOf := reflect.ValueOf(p.P.RemoteSignal)
	of := reflect.TypeOf(p.P.RemoteSignal)
	for i := 0; i < of.NumField(); i++ {
		fmt.Println(of.Field(i).Name, ":", valueOf.Field(i))
	}

	if p.P.RemoteSignal.PcsFaultState == 1 || p.P.RemoteSignal.BMSFaultState == 1 || p.P.RemoteSignal.PcsEmegstop == 1 {
		fmt.Println("pcs fault state:", p.P.RemoteSignal.PcsFaultState, "bms fault:", p.P.RemoteSignal.BMSFaultState, "pcs emeg stop:", p.P.RemoteSignal.PcsEmegstop)
		return false, false
	}
	if p.P.RemoteSignal.PcsAlarmState == 1 || p.P.RemoteMetering.BmsAlarmLevel > 2 || p.P.RemoteSignal.PcsCommState == 1 {
		fmt.Println("pcs alarm state:", p.P.RemoteSignal.PcsAlarmState, "bms alarm level:", p.P.RemoteMetering.BmsAlarmLevel, "pcs comm state:", p.P.RemoteSignal.PcsCommState)
		return false, true
	}
	if p.P.RemoteAdjRemoteCtrMng.RemoteCtrl.EnvironTemperProtect == 1 {
		if p.P.RemoteMetering.EnvironTemper > p.P.RemoteAdjRemoteCtrMng.RemoteCtrl.EnvironTemperProtect {
			fmt.Println("envi temper protect:", p.P.RemoteMetering.EnvironTemper)
			return false, true
		}
	}
	if p.P.RemoteAdjRemoteCtrMng.RemoteCtrl.CellMaxVolProtect == 1 {

	}
	if p.P.RemoteAdjRemoteCtrMng.RemoteCtrl.CellMinxVolProtect == 1 {

	}
	if p.P.RemoteAdjRemoteCtrMng.RemoteCtrl.BmsUPVolCtrl == 1 {

	}
	if p.P.RemoteAdjRemoteCtrMng.RemoteCtrl.PackMaxTemperProtect == 1 {

	}

	return true, true
}

func (p *Peak_load_shift) charge_proc() {
	_, file, line, _ := runtime.Caller(0)
	fmt.Printf("File: %s, Line: %d\n", file, line)
	ChDisMode := float32(p.P.RemoteAdjRemoteCtrMng.RemoteAdj.PowerPara.ChargeDischargeMode)
	if p.P.RemoteMetering.Soc >= p.P.RemoteAdjRemoteCtrMng.RemoteAdj.SocPara.SocMax || p.P.RemoteMetering.BmsAlarmLevel >= 2 {
		p.P.RunModeSel.PcsActivePowerSet(0)
	} else {
		f := p.P.CurrTimeline.Power * ChDisMode
		if p.P.RemoteAdjRemoteCtrMng.RemoteCtrl.GridCapaCtrl == 1 {
			f2 := float32(p.P.RemoteAdjRemoteCtrMng.RemoteAdj.TransPara.Ratio) *
				p.P.RemoteAdjRemoteCtrMng.RemoteAdj.TransPara.Capacity / 100

			if p.P.RemoteMetering.GridActivePower >= f2 {
				f = (f2 - p.P.RemoteMetering.LoadPower) * ChDisMode
			}
		}

		if p.P.RemoteAdjRemoteCtrMng.RemoteCtrl.GridDemandCtrl == 1 {

		}

		if p.P.RemoteMetering.ChargeStationPower != f {
			if float32(math.Abs(float64(f))) > p.P.RemoteAdjRemoteCtrMng.RemoteAdj.MaxChargePower {
				p.P.RunModeSel.PcsActivePowerSet(p.P.RemoteAdjRemoteCtrMng.RemoteAdj.MaxChargePower * float32(p.P.RemoteAdjRemoteCtrMng.RemoteAdj.PowerPara.ChargeDischargeMode))
			} else {
				p.P.RunModeSel.PcsActivePowerSet(f)
			}

		}
	}
}

func (p *Peak_load_shift) discharge_proc() {
	_, file, line, _ := runtime.Caller(0)
	fmt.Printf("File: %s, Line: %d\n", file, line)
	var f float32 = 0
	if p.P.RemoteMetering.Soc <= p.P.RemoteAdjRemoteCtrMng.RemoteAdj.SocPara.SocMin || p.P.RemoteMetering.BmsAlarmLevel >= 2 {
		p.P.RunModeSel.PcsActivePowerSet(0)
	} else {
		if p.P.RemoteAdjRemoteCtrMng.RemoteCtrl.AntiRefluxCtrl == 1 {
			if p.P.RemoteAdjRemoteCtrMng.RemoteAdj.AntiReflux.Mode == 0 {
				if p.P.RemoteMetering.GridActivePower < p.P.RemoteAdjRemoteCtrMng.RemoteAdj.AntiReflux.Start {
					f = p.P.RemoteMetering.GridActivePower + p.P.RemoteMetering.BmsActivePower*float32(p.P.RemoteAdjRemoteCtrMng.RemoteAdj.PowerPara.ChargeDischargeMode) -
						p.P.RemoteAdjRemoteCtrMng.RemoteAdj.AntiReflux.End
				} else if p.P.RemoteMetering.GridActivePower > p.P.RemoteAdjRemoteCtrMng.RemoteAdj.AntiReflux.Start &&
					p.P.RemoteMetering.GridActivePower < p.P.RemoteAdjRemoteCtrMng.RemoteAdj.AntiReflux.End {
					f = p.P.RemoteMetering.GridActivePower + p.P.RemoteMetering.BmsActivePower*float32(p.P.RemoteAdjRemoteCtrMng.RemoteAdj.PowerPara.ChargeDischargeMode) -
						p.P.RemoteAdjRemoteCtrMng.RemoteAdj.AntiReflux.End - p.P.RemoteAdjRemoteCtrMng.RemoteAdj.AntiReflux.Start
				} else {
					f = p.P.CurrTimeline.Power
				}
			} else {
				//pid计算.
				if p.P.RemoteMetering.GridActivePower < p.P.RemoteAdjRemoteCtrMng.RemoteAdj.AntiReflux.End {
					if p.P.RemoteAdjRemoteCtrMng.RemoteAdj.AntiReflux.PId == nil {
						p.P.RemoteAdjRemoteCtrMng.RemoteAdj.AntiReflux.PId = &pid.PID{}
						p.P.RemoteAdjRemoteCtrMng.RemoteAdj.AntiReflux.PId.Kp = p.P.RemoteAdjRemoteCtrMng.RemoteAdj.PIDPara.P
						p.P.RemoteAdjRemoteCtrMng.RemoteAdj.AntiReflux.PId.Ki = p.P.RemoteAdjRemoteCtrMng.RemoteAdj.PIDPara.I
						p.P.RemoteAdjRemoteCtrMng.RemoteAdj.AntiReflux.PId.Kd = p.P.RemoteAdjRemoteCtrMng.RemoteAdj.PIDPara.D
					}
					compute := p.P.RemoteAdjRemoteCtrMng.RemoteAdj.AntiReflux.PId.Compute(float64(p.P.RemoteAdjRemoteCtrMng.RemoteAdj.AntiReflux.End),
						float64(p.P.RemoteMetering.GridActivePower), 1)
					f = p.P.RemoteMetering.BmsActivePower*float32(p.P.RemoteAdjRemoteCtrMng.RemoteAdj.PowerPara.ChargeDischargeMode) + float32(compute)
				}
			}
			if f > p.P.CurrTimeline.Power {
				f = p.P.CurrTimeline.Power
			} else if f < 0 {
				f = 0
			}
		} else {
			f = p.P.CurrTimeline.Power
		}

		if p.P.RemoteAdjRemoteCtrMng.RemoteCtrl.GridDemandCtrl == 1 {

		}

		if p.P.RemoteMetering.ChargeStationPower != f {
			if float32(math.Abs(float64(f))) > p.P.RemoteAdjRemoteCtrMng.RemoteAdj.MaxDisChargePower {
				p.P.RunModeSel.PcsActivePowerSet(-1 * p.P.RemoteAdjRemoteCtrMng.RemoteAdj.MaxDisChargePower * float32(p.P.RemoteAdjRemoteCtrMng.RemoteAdj.PowerPara.ChargeDischargeMode))
			} else {
				p.P.RunModeSel.PcsActivePowerSet(-f * float32(p.P.RemoteAdjRemoteCtrMng.RemoteAdj.PowerPara.ChargeDischargeMode))
			}

		}
	}
}

func (p *Peak_load_shift) open_check_proc() bool {
	if p.P.RemoteSignal.PcsOpenState != 1 {
		p.P.RunModeSel.PcsActivePowerSet(0)
		p.P.RunModeSel.PcsOpenSet()
		fmt.Println("Pcs open state:", p.P.RemoteSignal.PcsOpenState)
		return false
	} else if p.P.RemoteSignal.PcsRunState == 1 {
		if p.P.RemoteSignal.PcsGridConnState == 1 {
			return true
		} else {
			fmt.Println("Pcs grid conn state is ", p.P.RemoteSignal.PcsGridConnState)
			return false
		}
	} else {
		return false
	}
}

func (p *Peak_load_shift) stop_proc() {
	_, file, line, _ := runtime.Caller(0)
	fmt.Printf("File: %s, Line: %d\n", file, line)
	//val, err := devdata.GetDevRegVal("PCS1", "yt", "T1")
	//fmt.Println("yt:t1", val, err)
	if p.P.RemoteSignal.PcsOpenState == 1 {
		p.P.RunModeSel.PcsCloseSet()
		p.P.RunModeSel.PcsActivePowerSet(0)
	}
}

func (p *Peak_load_shift) idle_proc() {
	_, file, line, _ := runtime.Caller(0)
	fmt.Printf("File: %s, Line: %d\n", file, line)
	if p.P.RemoteMetering.ChargeStationPower != 0 {
		p.P.RunModeSel.PcsActivePowerSet(0)
	}
}

func (p *Peak_load_shift) discharge_trace_proc() {
	_, file, line, _ := runtime.Caller(0)
	fmt.Printf("File: %s, Line: %d\n", file, line)
	if p.P.RemoteMetering.Soc <= p.P.RemoteAdjRemoteCtrMng.RemoteAdj.SocPara.SocMin {
		p.P.RunModeSel.PcsActivePowerSet(0)
		return
	}
	load := p.P.RemoteMetering.GridActivePower - p.P.RemoteMetering.BmsActivePower*float32(p.P.RemoteAdjRemoteCtrMng.RemoteAdj.PowerPara.ChargeDischargeMode)
	load = load * float32(p.P.CurrTimeline.Ratio) / 100
	if load > p.P.CurrTimeline.Power {
		load = p.P.CurrTimeline.Power
	}

	if load > p.P.RemoteAdjRemoteCtrMng.RemoteAdj.MaxDisChargePower {
		load = p.P.RemoteAdjRemoteCtrMng.RemoteAdj.MaxDisChargePower
	}
	load *= float32(p.P.RemoteAdjRemoteCtrMng.RemoteAdj.PowerPara.ChargeDischargeMode)
	p.P.RunModeSel.PcsActivePowerSet(-load)
}

func (p *Peak_load_shift) discharge_trace_diff() {
	_, file, line, _ := runtime.Caller(0)
	fmt.Printf("File: %s, Line: %d\n", file, line)

	if p.P.RemoteMetering.Soc <= p.P.RemoteAdjRemoteCtrMng.RemoteAdj.SocPara.SocMin {
		p.P.RunModeSel.PcsActivePowerSet(0)
		return
	}

	load := p.P.RemoteMetering.GridActivePower - p.P.RemoteMetering.BmsActivePower*float32(p.P.RemoteAdjRemoteCtrMng.RemoteAdj.PowerPara.ChargeDischargeMode)
	load = load * float32(p.P.CurrTimeline.Ratio) / 100
	if load > p.P.CurrTimeline.TrackPower {
		load -= p.P.CurrTimeline.TrackPower
	}

	if load > p.P.CurrTimeline.Power {
		load = p.P.CurrTimeline.Power
	}

	if load > p.P.RemoteAdjRemoteCtrMng.RemoteAdj.MaxDisChargePower {
		load = p.P.RemoteAdjRemoteCtrMng.RemoteAdj.MaxDisChargePower
	}
	load *= float32(p.P.RemoteAdjRemoteCtrMng.RemoteAdj.PowerPara.ChargeDischargeMode)
	p.P.RunModeSel.PcsActivePowerSet(-load)
}

func (p *Peak_load_shift) Policy_Process() {
	//TODO implement me
	fmt.Println("Policy_Process me")
	switch p.P.CurrTimeline.Mode {
	case public.CTRL_STOP:
		p.stop_proc()
	case public.CTRL_CHARGE:
		proc := p.open_check_proc()
		if proc == true {
			p.charge_proc()
		}
	case public.CTRL_DISCHARGE:
		proc := p.open_check_proc()
		if proc == true {
			p.discharge_proc()
		}

	case public.CTRL_IDLE:
		proc := p.open_check_proc()
		if proc == true {
			p.idle_proc()
		}
	case public.CTRL_DISCHAGET_TRACE:
		proc := p.open_check_proc()
		if proc == true {
			p.discharge_trace_proc()
		}
	case public.CTRL_CHARGE_PV_TRACE:
		fmt.Println("not support")
	case public.CTRL_DISCHARGE_TRACE_DIFF:
		proc := p.open_check_proc()
		if proc == true {
			p.discharge_trace_diff()
		}
	}
}
